package com.example.demolearn.reflection;

import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.List;

public class ReflectionLearn {

    // 通过一个字符串得到一个类
    public void getClassByString() {
        String abc = "abcdefg";
        Class c1 = abc.getClass();
        System.out.println(c1.getName());
    }

    // 通过字符串定义载入类
    public void setClassForString() throws ClassNotFoundException {
        String name = "java.lang.String";  // 找不到类会报错
        Class c1 = null;
        c1 = Class.forName(name);
        System.out.println(c1.getName());
    }

    // 通过反射获取Test类的构造方法
    public void getConstructorsByTest() {
        Test test = new Test();
        Class c1 = test.getClass();
        Constructor[] cons = c1.getDeclaredConstructors();
//        Constructor[] cons = c1.getConstructors();    这个是获取全部public的
        /**
         * getModifiers(),返回的是数字
         * Modifier.toString，映射出public这种类型
         * */
        List listConstruction = new ArrayList();
        List listModify = new ArrayList();   // 构造方法类型
        List listParam = new ArrayList();   // 构造方法参数
        for(int i = 0; i < cons.length; i++) {
            listConstruction.add(cons[i]);
            listModify.add(Modifier.toString(cons[i].getModifiers()));
        }
//        System.out.println(listConstruction);
//        System.out.println(listModify);
    }

    // 通过参数获取特定的构造方法
    public void getConstructorByParam() {
        Test test = new Test();
        Class c1 = test.getClass();
        try {
            // 因为不一定有这个方法，所以要捕捉异常
            // 不带参
            Constructor con = c1.getDeclaredConstructor();
            System.out.println(con);
            // 带2个参数
            Class[] param = {int.class, String.class};
            Constructor con1 = c1.getDeclaredConstructor(param);
            System.out.println(con1);
            // 带1个参数
            Class param1 = String.class;
            Constructor con2 = c1.getDeclaredConstructor(param1);
//            Constructor con2 = c1.getConstructor(param1);  // 这个只能获取到public的，不是会报错
            System.out.println(con2);

        }catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }

    // 调用构造方法
    public Object callConstructor() {
        // 调用2个参数的
        Test test = new Test();
        Class c1 = test.getClass();
        try{
            Constructor con1 = c1.getDeclaredConstructor(new Class[]{int.class, String.class});
            // 通过newInstance调用
            con1.newInstance(12, "Tom");
            Constructor con2 = c1.getDeclaredConstructor(String.class);
            con2.setAccessible(true); // 调用私有方法需要加上这个
            Object o = con2.newInstance("Amy");
            return o;
        }catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return test;
    }

    // 调用方法
    public void callMethods(Object o) {
        Test test = new Test();
        Class c1 = o.getClass();
        try {
            Method method = c1.getDeclaredMethod("welcome", String.class);
            method.setAccessible(true);  // 私有方法需要设这个
            //参数
            Object[] args = {"欢迎来到英雄联盟"};
            // 普通方法是使用invoke
            // 注意，实例的test当然不能new出来，可以是用newInstance
            method.invoke(o, args);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    // 获取类的私有字段
    public void getPropertyPrimary(Object o) {
        Test test = new Test();
        Class c1 = test.getClass();
        // 获取字段Field
        Field field = null;
        try {
            field = c1.getDeclaredField("name");
            field.setAccessible(true);
            try {
                field.set(o, "傻子");
                System.out.println(field.get(o).toString());
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) throws ClassNotFoundException {
        ReflectionLearn rl = new ReflectionLearn();
        rl.getClassByString();
        rl.setClassForString();
        rl.getConstructorsByTest();
        rl.getConstructorByParam();
        Object o = rl.callConstructor();
        rl.callMethods(o);
        rl.getPropertyPrimary(o);
    }
}
